---
type: integration
title: '@astrojs/sitemap'
description: Learn how to use the @astrojs/sitemap integration in your Astro project.
githubIntegrationURL: 'https://github.com/withastro/astro/tree/main/packages/integrations/sitemap/'
category: other
i18nReady: true
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';

This **[Astro integration][astro-integration]** generates a sitemap based on your pages when you build your Astro project.

## Why Astro Sitemap

A Sitemap is an XML file that outlines all of the pages, videos, and files on your site. Search engines like Google read this file to crawl your site more efficiently. [See Google's own advice on sitemaps](https://developers.google.com/search/docs/advanced/sitemaps/overview) to learn more.

A sitemap file is recommended for large multi-page sites. If you don't use a sitemap, most search engines will still be able to list your site's pages, but a sitemap is a great way to ensure that your site is as search engine friendly as possible.

With Astro Sitemap, you don't have to worry about creating this XML file yourself: the Astro Sitemap integration will crawl your statically-generated routes and create the sitemap file, including [dynamic routes](/en/guides/routing/#dynamic-routes) like `[...slug]` or `src/pages/[lang]/[version]/info.astro` generated by `getStaticPaths()`.

This integration cannot generate sitemap entries for dynamic routes in [SSR mode](/en/basics/rendering-modes/#on-demand-rendered).

## Installation

Astro includes an `astro add` command to automate the setup of official integrations. If you prefer, you can [install integrations manually](#manual-install) instead.

Run one of the following commands in a new terminal window.

<PackageManagerTabs>
  <Fragment slot="npm">
  ```sh
  npx astro add sitemap
  ```
  </Fragment>
  <Fragment slot="pnpm">
  ```sh
  pnpm astro add sitemap
  ```
  </Fragment>
  <Fragment slot="yarn">
  ```sh
  yarn astro add sitemap
  ```
  </Fragment>
</PackageManagerTabs>

If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.

### Manual Install

First, install the `@astrojs/sitemap` package using your package manager.

<PackageManagerTabs>
  <Fragment slot="npm">
  ```sh
  npm install @astrojs/sitemap
  ```
  </Fragment>
  <Fragment slot="pnpm">
  ```sh
  pnpm add @astrojs/sitemap
  ```
  </Fragment>
  <Fragment slot="yarn">
  ```sh
  yarn add @astrojs/sitemap
  ```
  </Fragment>
</PackageManagerTabs>

Then, apply the integration to your `astro.config.*` file using the `integrations` property:

```js ins={2} ins="sitemap()"
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  // ...
  integrations: [sitemap()],
});
```

## Usage

`@astrojs/sitemap` requires a deployment / site URL for generation. Add your site's URL under your `astro.config.*` using the `site` property. This must begin with `http:` or `https:`.

```js title="astro.config.mjs" "'https://stargazers.club'"
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  // ...
  site: 'https://stargazers.club',
  integrations: [sitemap()],
});
```

Note that unlike other configuration options, `site` is set in the root `defineConfig` object, rather than inside the `sitemap()` call.

Now, [build your site for production](/en/reference/cli-reference/#astro-build) via the `astro build` command. You will find both `sitemap-index.xml` and `sitemap-0.xml` in the `dist/` folder (or your custom [output directory](/en/reference/configuration-reference/#outdir) if set).

:::caution
If you forget to add a `site`, you'll get a friendly warning when you build, and the `sitemap-index.xml` file won't be generated.
:::

After verifying that the sitemaps are built, you can add them to your site's `<head>` and the `robots.txt` file for crawlers to pick up.

```html title="src/layouts/Layout.astro" ins={2}
<head>
  <link rel="sitemap" href="/sitemap-index.xml" />
</head>
```

```txt ins={5}
# public/robots.txt
User-agent: *
Allow: /

Sitemap: https://<YOUR SITE>/sitemap-index.xml
```

To generate `robots.txt` dynamically, add a file named `robots.txt.ts` with the following code:

```ts title="src/pages/robots.txt.ts"
import type { APIRoute } from 'astro';

const robotsTxt = `
User-agent: *
Allow: /

Sitemap: ${new URL('sitemap-index.xml', import.meta.env.SITE).href}
`.trim();

export const GET: APIRoute = () => {
  return new Response(robotsTxt, {
    headers: {
      'Content-Type': 'text/plain; charset=utf-8',
    },
  });
};

```

### Example of generated files for a two-page website

```xml title="sitemap-index.xml"
<?xml version="1.0" encoding="UTF-8"?>
  <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://stargazers.club/sitemap-0.xml</loc>
  </sitemap>
</sitemapindex>
```

```xml title="sitemap-0.xml"
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
  <url>
    <loc>https://stargazers.club/</loc>
  </url>
  <url>
    <loc>https://stargazers.club/second-page/</loc>
  </url>
</urlset>
```

## Configuration

To configure this integration, pass an object to the `sitemap()` function call in `astro.config.mjs`.

```js title="astro.config.mjs" {6-8}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  integrations: [
    sitemap({
      // configuration options
    }),
  ],
});
```

### filter

All pages are included in your sitemap by default. By adding a custom `filter` function, you can filter included pages by URL.

```js title="astro.config.mjs" ins={8}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      filter: (page) => page !== 'https://stargazers.club/secret-vip-lounge/',
    }),
  ],
});
```

The function will be called for every page on your site. The `page` function parameter is the full URL of the page currently under consideration, including your `site` domain. Return `true` to include the page in your sitemap, and `false` to leave it out.

To filter multiple pages, add arguments with target URLs.

```js title="astro.config.mjs" {8-12}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      filter: (page) =>
        page !== 'https://stargazers.club/secret-vip-lounge-1/' &&
        page !== 'https://stargazers.club/secret-vip-lounge-2/' &&
        page !== 'https://stargazers.club/secret-vip-lounge-3/' &&
        page !== 'https://stargazers.club/secret-vip-lounge-4/',
    }),
  ],
});
```

### customPages

In some cases, a page might be part of your deployed site but not part of your Astro project. If you'd like to include a page in your sitemap that *isn't* created by Astro, you can use this option.

```js title="astro.config.mjs" ins={8}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      customPages: ['https://stargazers.club/external-page', 'https://stargazers.club/external-page2'],
    }),
  ],
});
```

### entryLimit

The maximum number entries per sitemap file. The default value is 45000. A sitemap index and multiple sitemaps are created if you have more entries. See this [explanation of splitting up a large sitemap](https://developers.google.com/search/docs/advanced/sitemaps/large-sitemaps).

```js title="astro.config.mjs" ins={8}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      entryLimit: 10000,
    }),
  ],
});
```

### changefreq, lastmod, and priority

These options correspond to the `<changefreq>`, `<lastmod>`, and `<priority>` tags in the [Sitemap XML specification.](https://www.sitemaps.org/protocol.html)

Note that `changefreq` and `priority` are ignored by Google.

:::note
Due to limitations of Astro's [Integration API](/en/reference/integrations-reference/), this integration can't analyze a given page's source code. This configuration option can set `changefreq`, `lastmod` and `priority` on a *site-wide* basis; see the next option **serialize** for how you can set these values on a per-page basis.
:::

```js title="astro.config.mjs" ins={8-10}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      changefreq: 'weekly',
      priority: 0.7,
      lastmod: new Date('2022-02-24'),
    }),
  ],
});
```

### serialize

A function called for each sitemap entry just before writing to a disk. This function can be asynchronous.

It receives as its parameter a `SitemapItem` object that can have these properties:

* `url` (absolute page URL). This is the only property that is guaranteed to be on `SitemapItem`.
* `changefreq`
* `lastmod` (ISO formatted date, `String` type)
* `priority`
* `links`.

This `links` property contains a `LinkItem` list of alternate pages including a parent page.

The `LinkItem` type has two fields: `url` (the fully-qualified URL for the version of this page for the specified language) and `lang` (a supported language code targeted by this version of the page).

The `serialize` function should return `SitemapItem`, touched or not.

The example below shows the ability to add sitemap specific properties individually.

```js title="astro.config.mjs" ins={8-18}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      serialize(item) {
        if (/exclude-from-sitemap/.test(item.url)) {
          return undefined;
        }
        if (/your-special-page/.test(item.url)) {
          item.changefreq = 'daily';
          item.lastmod = new Date();
          item.priority = 0.9;
        }
        return item;
      },
    }),
  ],
});
```

### i18n

To localize a sitemap, pass an object to this `i18n` option.

This object has two required properties:

* `defaultLocale`: `String`. Its value must exist as one of `locales` keys.
* `locales`: `Record<String, String>`, key/value - pairs. The key is used to look for a locale part in a page path. The value is a language attribute, only English alphabet and hyphen allowed.

[Read more about language attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang).

[Read more about localization](https://developers.google.com/search/docs/advanced/crawling/localized-versions#all-method-guidelines).

```js title="astro.config.mjs" ins={8-15}
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://stargazers.club',
  integrations: [
    sitemap({
      i18n: {
        defaultLocale: 'en', // All urls that don't contain `es` or `fr` after `https://stargazers.club/` will be treated as default locale, i.e. `en`
        locales: {
          en: 'en-US', // The `defaultLocale` value must present in `locales` keys
          es: 'es-ES',
          fr: 'fr-CA',
        },
      },
    }),
  ],
});
```

The resulting sitemap looks like this:

```xml title="sitemap-0.xml"
...
  <url>
    <loc>https://stargazers.club/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://stargazers.club/"/>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://stargazers.club/es/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://stargazers.club/fr/"/>
  </url>
  <url>
    <loc>https://stargazers.club/es/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://stargazers.club/"/>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://stargazers.club/es/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://stargazers.club/fr/"/>
  </url>
  <url>
    <loc>https://stargazers.club/fr/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://stargazers.club/"/>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://stargazers.club/es/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://stargazers.club/fr/"/>
  </url>
  <url>
    <loc>https://stargazers.club/es/second-page/</loc>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://stargazers.club/es/second-page/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://stargazers.club/fr/second-page/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://stargazers.club/second-page/"/>
  </url>
...
```

## Examples

* The official Astro website uses Astro Sitemap to generate [its sitemap](https://astro.build/sitemap-index.xml).
* [Browse projects with Astro Sitemap on GitHub](https://github.com/search?q=%22%40astrojs%2Fsitemap%22+path%3Apackage.json\&type=Code) for more examples!

[astro-integration]: /en/guides/integrations-guide/
